﻿// Decompiled with JetBrains decompiler
// Type: DnProcessSimulateCommands.InterferenceVolumeQuery.Tree.TreeNode
// Assembly: DnProcessSimulateCommands, Version=2402.0.0.890, Culture=neutral, PublicKeyToken=null
// MVID: A885D881-AEDF-447E-852A-6F13102E089C
// Assembly location: C:\Program Files\Tecnomatix_2402\eMPower\DotNetCommands\DnProcessSimulateCommands.dll

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;


namespace DnProcessSimulateCommands.InterferenceVolumeQuery.Tree;

public sealed class TreeNode : INotifyPropertyChanged
{
  private TreeList _tree;
  private INotifyCollectionChanged _childrenSource;
  private int _index = -1;
  private bool _isExpanded;
  private bool _isSelected;
  private TreeNode _parent;
  private object _tag;
  private Collection<TreeNode> _children;
  private ReadOnlyCollection<TreeNode> _nodes;

  public event PropertyChangedEventHandler PropertyChanged;

  private void OnPropertyChanged(string name)
  {
    if (this.PropertyChanged == null)
      return;
    this.PropertyChanged((object) this, new PropertyChangedEventArgs(name));
  }

  internal TreeList Tree => this._tree;

  internal INotifyCollectionChanged ChildrenSource
  {
    get => this._childrenSource;
    set
    {
      if (this._childrenSource != null)
        this._childrenSource.CollectionChanged -= new NotifyCollectionChangedEventHandler(this.ChildrenChanged);
      this._childrenSource = value;
      if (this._childrenSource == null)
        return;
      this._childrenSource.CollectionChanged += new NotifyCollectionChangedEventHandler(this.ChildrenChanged);
    }
  }

  public int Index => this._index;

  internal bool IsVisible
  {
    get
    {
      for (TreeNode parent = this._parent; parent != null; parent = parent.Parent)
      {
        if (!parent.IsExpanded)
          return false;
      }
      return true;
    }
  }

  public bool IsExpandedOnce { get; internal set; }

  public bool HasChildren { get; internal set; }

  public bool IsExpanded
  {
    get => this._isExpanded;
    set
    {
      if (value == this.IsExpanded)
        return;
      this.Tree.SetIsExpanded(this, value);
      this.OnPropertyChanged(nameof (IsExpanded));
      this.OnPropertyChanged("IsExpandable");
    }
  }

  internal void AssignIsExpanded(bool value) => this._isExpanded = value;

  public bool IsExpandable => this.HasChildren && !this.IsExpandedOnce || this.Nodes.Count > 0;

  public bool IsSelected
  {
    get => this._isSelected;
    set
    {
      if (value == this._isSelected)
        return;
      this._isSelected = value;
      this.OnPropertyChanged(nameof (IsSelected));
    }
  }

  public TreeNode Parent => this._parent;

  public int Level => this._parent == null ? -1 : this._parent.Level + 1;

  public TreeNode PreviousNode
  {
    get
    {
      if (this._parent != null)
      {
        int index = this.Index;
        if (index > 0)
          return this._parent.Nodes[index - 1];
      }
      return (TreeNode) null;
    }
  }

  public TreeNode NextNode
  {
    get
    {
      if (this._parent != null)
      {
        int index = this.Index;
        if (index < this._parent.Nodes.Count - 1)
          return this._parent.Nodes[index + 1];
      }
      return (TreeNode) null;
    }
  }

  internal TreeNode BottomNode
  {
    get
    {
      TreeNode parent = this.Parent;
      if (parent == null)
        return (TreeNode) null;
      return parent.NextNode != null ? parent.NextNode : parent.BottomNode;
    }
  }

  internal TreeNode NextVisibleNode
  {
    get
    {
      return this.IsExpanded && this.Nodes.Count > 0 ? this.Nodes[0] : this.NextNode ?? this.BottomNode;
    }
  }

  public int VisibleChildrenCount => this.AllVisibleChildren.Count<TreeNode>();

  public IEnumerable<TreeNode> AllVisibleChildren
  {
    get
    {
      TreeNode treeNode = this;
      int level = treeNode.Level;
      TreeNode node = treeNode;
      while (true)
      {
        node = node.NextVisibleNode;
        if (node != null && node.Level > level)
          yield return node;
        else
          break;
      }
    }
  }

  public object Tag => this._tag;

  internal Collection<TreeNode> Children => this._children;

  public ReadOnlyCollection<TreeNode> Nodes => this._nodes;

  internal TreeNode(TreeList tree, object tag)
  {
    this._tree = tree != null ? tree : throw new ArgumentNullException(nameof (tree));
    this._children = (Collection<TreeNode>) new TreeNode.NodeCollection(this);
    this._nodes = new ReadOnlyCollection<TreeNode>((IList<TreeNode>) this._children);
    this._tag = tag;
  }

  public override string ToString() => this.Tag != null ? this.Tag.ToString() : base.ToString();

  private void ChildrenChanged(object sender, NotifyCollectionChangedEventArgs e)
  {
    switch (e.Action)
    {
      case NotifyCollectionChangedAction.Add:
        if (e.NewItems != null)
        {
          int newStartingIndex = e.NewStartingIndex;
          int rowIndex = this.Tree.Rows.IndexOf(this);
          if (rowIndex == -1)
            rowIndex = this.Tree.Rows.Count - newStartingIndex - 1;
          IEnumerator enumerator = e.NewItems.GetEnumerator();
          try
          {
            while (enumerator.MoveNext())
            {
              this.Tree.InsertNewNode(this, enumerator.Current, rowIndex, newStartingIndex);
              ++newStartingIndex;
            }
            break;
          }
          finally
          {
            if (enumerator is IDisposable disposable)
              disposable.Dispose();
          }
        }
        else
          break;
      case NotifyCollectionChangedAction.Remove:
        if (this.Children.Count > e.OldStartingIndex)
        {
          this.RemoveChildAt(e.OldStartingIndex);
          break;
        }
        break;
      case NotifyCollectionChangedAction.Replace:
      case NotifyCollectionChangedAction.Move:
      case NotifyCollectionChangedAction.Reset:
        while (this.Children.Count > 0)
          this.RemoveChildAt(0);
        this.Tree.CreateChildrenNodes(this);
        break;
    }
    this.HasChildren = this.Children.Count > 0;
    this.OnPropertyChanged("IsExpandable");
  }

  private void RemoveChildAt(int index)
  {
    TreeNode child = this.Children[index];
    this.Tree.DropChildrenRows(child, true);
    this.ClearChildrenSource(child);
    this.Children.RemoveAt(index);
  }

  private void ClearChildrenSource(TreeNode node)
  {
    node.ChildrenSource = (INotifyCollectionChanged) null;
    foreach (TreeNode child in node.Children)
      this.ClearChildrenSource(child);
  }

  private class NodeCollection : Collection<TreeNode>
  {
    private TreeNode _owner;

    public NodeCollection(TreeNode owner) => this._owner = owner;

    protected override void ClearItems()
    {
      while (this.Count != 0)
        this.RemoveAt(this.Count - 1);
    }

    protected override void InsertItem(int index, TreeNode item)
    {
      if (item == null)
        throw new ArgumentNullException(nameof (item));
      if (item.Parent == this._owner)
        return;
      if (item.Parent != null)
        item.Parent.Children.Remove(item);
      item._parent = this._owner;
      item._index = index;
      for (int index1 = index; index1 < this.Count; ++index1)
        ++this[index1]._index;
      base.InsertItem(index, item);
    }

    protected override void RemoveItem(int index)
    {
      TreeNode treeNode = this[index];
      treeNode._parent = (TreeNode) null;
      treeNode._index = -1;
      for (int index1 = index + 1; index1 < this.Count; ++index1)
        --this[index1]._index;
      base.RemoveItem(index);
    }

    protected override void SetItem(int index, TreeNode item)
    {
      if (item == null)
        throw new ArgumentNullException(nameof (item));
      this.RemoveAt(index);
      this.InsertItem(index, item);
    }
  }
}
